// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
//
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.ui.prefs;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.dengues.core.i18n.Messages;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf Qiang.Zhang.Adolf@gmail.com 2008-5-4 qiang.zhang $
 * 
 */
public abstract class StructuredViewerAndButtons extends Composite {

    public static int ADD_BUTTON = 1 << 1;

    public static int REMOVE_BUTTON = 1 << 2;

    public static int EDIT_BUTTON = 1 << 3;

    public static int UP_BUTTON = 1 << 4;

    public static int DOWN_BUTTON = 1 << 5;

    public static int COPY_BUTTON = 1 << 6;

    private FontMetrics fontMetrics;

    private StructuredViewer viewer;

    private Composite groupComponent;

    protected Map<Integer, Button> butonsMap;

    protected Map<Integer, Action> actionsMap;

    /**
     * Qiang.Zhang.Adolf@gmail.com StructuredViewerAndButtons constructor comment.
     * 
     * @param parent
     * @param style
     * @param bottons
     */
    public StructuredViewerAndButtons(Composite parent, int style, int bottons) {
        super(parent, style);
        butonsMap = new HashMap<Integer, Button>();
        actionsMap = new HashMap<Integer, Action>();
        initializeDialogUnits(parent);
        createContents(bottons);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createContents".
     */
    private void createContents(int bottons) {
        GridLayout layout = new GridLayout();
        layout.numColumns = 2;
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        setLayout(layout);
        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        data.heightHint = 160;
        setLayoutData(data);
        viewer = createStructuredViewer(this);
        data = new GridData(GridData.FILL_BOTH);
        viewer.getControl().setLayoutData(data);
        viewer.addSelectionChangedListener(new ISelectionChangedListener() {

            public void selectionChanged(SelectionChangedEvent event) {
                StructuredSelection selection = (StructuredSelection) viewer.getSelection();
                if (selection != null && selection.size() > 0 && selection.getFirstElement() != null) {
                    updateButtons(selection.getFirstElement());
                } else {
                    updateButtons(null);
                }
            }

        });

        viewer.addDoubleClickListener(new IDoubleClickListener() {

            public void doubleClick(DoubleClickEvent event) {
                StructuredSelection selection = (StructuredSelection) viewer.getSelection();
                editButtonAction(selection);
            }
        });

        groupComponent = new Composite(this, SWT.NULL);
        GridLayout groupLayout = new GridLayout();
        groupLayout.marginWidth = 0;
        groupLayout.marginHeight = 0;
        groupComponent.setLayout(groupLayout);
        data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        groupComponent.setLayoutData(data);

        if ((bottons & ADD_BUTTON) != 0) {
            butonsMap.put(ADD_BUTTON, createAddButton());
            actionsMap.put(ADD_BUTTON, new Action(Messages.getString("ConnectivitySettingsPrefsPage.add")) {//$NON-NLS-1$

                        @Override
                        public void run() {
                            addButtonAction((StructuredSelection) viewer.getSelection());
                        }
                    });
        }
        if ((bottons & EDIT_BUTTON) != 0) {
            butonsMap.put(EDIT_BUTTON, createEditButton());
            actionsMap.put(EDIT_BUTTON, new Action(Messages.getString("ConnectivitySettingsPrefsPage.edit")) {//$NON-NLS-1$

                        @Override
                        public void run() {
                            editButtonAction((StructuredSelection) viewer.getSelection());
                        }
                    });
        }
        if ((bottons & REMOVE_BUTTON) != 0) {
            butonsMap.put(REMOVE_BUTTON, createRemoveButton());
            actionsMap.put(REMOVE_BUTTON, new Action(Messages.getString("ConnectivitySettingsPrefsPage.remove")) {//$NON-NLS-1$

                        @Override
                        public void run() {
                            removeButtonAction((StructuredSelection) viewer.getSelection());
                        }
                    });
        }
        if ((bottons & COPY_BUTTON) != 0) {
            butonsMap.put(COPY_BUTTON, createCopyButton());
            actionsMap.put(COPY_BUTTON, new Action(Messages.getString("ConnectivitySettingsPrefsPage.copy")) {//$NON-NLS-1$

                        @Override
                        public void run() {
                            copyButtonAction((StructuredSelection) viewer.getSelection());
                        }
                    });
        }
        if ((bottons & UP_BUTTON) != 0) {
            butonsMap.put(UP_BUTTON, createUpButton());
        }
        if ((bottons & DOWN_BUTTON) != 0) {
            butonsMap.put(DOWN_BUTTON, createDownButton());
        }
        hookContextMenu();
        updateButtons(null);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "hookContextMenu".
     */
    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {

            public void menuAboutToShow(IMenuManager manager) {
                Collection<Action> values = actionsMap.values();
                for (Action action : values) {
                    manager.add(action);
                }
            }
        });
        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "updateButtons".
     * 
     * @param object
     */
    protected void updateButtons(Object object) {
        if (object == null) {
            Collection<Button> values = butonsMap.values();
            for (Button button : values) {
                button.setEnabled(false);
            }
            Button button = butonsMap.get(ADD_BUTTON);
            if (button != null) {
                button.setEnabled(true);
            }
            Collection<Action> values2 = actionsMap.values();
            for (Action action : values2) {
                action.setEnabled(false);
            }
            Action action = actionsMap.get(ADD_BUTTON);
            if (action != null) {
                action.setEnabled(true);
            }
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createCopyButton".
     */
    private Button createCopyButton() {
        GridData data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        Button addButton = new Button(groupComponent, SWT.PUSH);
        addButton.setText(Messages.getString("ConnectivitySettingsPrefsPage.copy")); //$NON-NLS-1$
        addButton.setLayoutData(data);
        setButtonLayoutData(addButton);
        addButton.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                copyButtonAction((StructuredSelection) viewer.getSelection());
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }

        });
        return addButton;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "copyButtonAction".
     * 
     * @param selection
     */
    protected void copyButtonAction(StructuredSelection selection) {

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createDownButton".
     */
    private Button createDownButton() {
        GridData data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        Button addButton = new Button(groupComponent, SWT.PUSH);
        addButton.setText("Down");
        addButton.setLayoutData(data);
        setButtonLayoutData(addButton);
        addButton.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                downButtonAction((StructuredSelection) viewer.getSelection());
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }

        });
        return addButton;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "downButtonAction".
     * 
     * @param selection
     */
    protected void downButtonAction(StructuredSelection selection) {

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createUpButton".
     */
    private Button createUpButton() {
        GridData data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        Button addButton = new Button(groupComponent, SWT.PUSH);
        addButton.setText("Up");
        addButton.setLayoutData(data);
        setButtonLayoutData(addButton);
        addButton.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                upButtonAction((StructuredSelection) viewer.getSelection());
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }

        });
        return addButton;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "upButtonAction".
     * 
     * @param selection
     */
    protected void upButtonAction(StructuredSelection selection) {

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createRemovwButton".
     */
    private Button createRemoveButton() {
        GridData data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        Button addButton = new Button(groupComponent, SWT.PUSH);
        addButton.setText(Messages.getString("ConnectivitySettingsPrefsPage.remove")); //$NON-NLS-1$
        addButton.setLayoutData(data);
        setButtonLayoutData(addButton);
        addButton.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                removeButtonAction((StructuredSelection) viewer.getSelection());
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }

        });
        return addButton;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "removeButtonAction".
     * 
     * @param selection
     */
    protected void removeButtonAction(StructuredSelection selection) {

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createEditButton".
     */
    private Button createEditButton() {
        GridData data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        Button editButton = new Button(groupComponent, SWT.PUSH);
        editButton.setText(Messages.getString("ConnectivitySettingsPrefsPage.edit")); //$NON-NLS-1$
        editButton.setLayoutData(data);
        setButtonLayoutData(editButton);
        editButton.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                editButtonAction((StructuredSelection) viewer.getSelection());
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }

        });
        return editButton;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "editButtonAction".
     * 
     * @param selection
     */
    protected void editButtonAction(StructuredSelection selection) {

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createAddButton".
     */
    private Button createAddButton() {
        GridData data = new GridData();
        data.verticalAlignment = GridData.FILL;
        data.horizontalAlignment = GridData.FILL;
        Button addButton = new Button(groupComponent, SWT.PUSH);
        addButton.setText(Messages.getString("ConnectivitySettingsPrefsPage.add")); //$NON-NLS-1$
        addButton.setLayoutData(data);
        setButtonLayoutData(addButton);
        addButton.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                addButtonAction((StructuredSelection) viewer.getSelection());
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }

        });
        return addButton;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "addDriver".
     * 
     * @param selection
     */
    protected void addButtonAction(StructuredSelection selection) {

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createStructuredViewer".
     * 
     * @param parent
     */
    public abstract StructuredViewer createStructuredViewer(Composite parent);

    /**
     * Sets the <code>GridData</code> on the specified button to be one that is spaced for the current dialog page
     * units. The method <code>initializeDialogUnits</code> must be called once before calling this method for the
     * first time.
     * 
     * @param button the button to set the <code>GridData</code>
     * @return the <code>GridData</code> set on the specified button
     */
    protected GridData setButtonLayoutData(Button button) {
        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
        int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
        Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
        data.widthHint = Math.max(widthHint, minSize.x);
        button.setLayoutData(data);
        return data;
    }

    /**
     * Initializes the computation of horizontal and vertical dialog units based on the size of current font.
     * <p>
     * This method must be called before any of the dialog unit based conversion methods are called.
     * </p>
     * 
     * @param testControl a control from which to obtain the current font
     */
    protected void initializeDialogUnits(Control testControl) {
        // Compute and store a font metric
        GC gc = new GC(testControl);
        gc.setFont(JFaceResources.getDialogFont());
        fontMetrics = gc.getFontMetrics();
        gc.dispose();
    }

    /**
     * Returns the number of pixels corresponding to the given number of horizontal dialog units.
     * <p>
     * This method may only be called after <code>initializeDialogUnits</code> has been called.
     * </p>
     * <p>
     * Clients may call this framework method, but should not override it.
     * </p>
     * 
     * @param dlus the number of horizontal dialog units
     * @return the number of pixels
     */
    protected int convertHorizontalDLUsToPixels(int dlus) {
        // test for failure to initialize for backward compatibility
        if (fontMetrics == null) {
            return 0;
        }
        return Dialog.convertHorizontalDLUsToPixels(fontMetrics, dlus);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "setInput".
     * 
     * @param data
     */
    public void setInput(Object data) {
        viewer.setInput(data);
    }
}
